/*!
    \copyright  Copyright (c) 2023-2025 Qualcomm Technologies International, Ltd.
                All Rights Reserved.
                Qualcomm Technologies International, Ltd. Confidential and Proprietary.
    \file
    \addtogroup le_bap
    \brief
    @{
*/

#if (defined(INCLUDE_LE_AUDIO_UNICAST) || defined(INCLUDE_LE_AUDIO_BROADCAST))
#include "pacs_audio_locations.h"
#include "pacs_utilities.h"
#include "multidevice.h"

#include <bap_server_prim.h>
#include <logging.h>
#include <panic.h>

#define ALL_AUDIO_LOCATIONS     ( AUDIO_LOCATION_MONO \
                                | AUDIO_LOCATION_FRONT_LEFT \
                                | AUDIO_LOCATION_FRONT_RIGHT \
                                | AUDIO_LOCATION_FRONT_CENTER \
                                | AUDIO_LOCATION_LOW_FREQUENCY_EFFECT1 \
                                | AUDIO_LOCATION_BACK_LEFT \
                                | AUDIO_LOCATION_BACK_RIGHT \
                                | AUDIO_LOCATION_FRONT_LEFT_OF_CENTER \
                                | AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER \
                                | AUDIO_LOCATION_BACK_CENTER \
                                | AUDIO_LOCATION_LOW_FREQUENCY_EFFECT2 \
                                | AUDIO_LOCATION_SIDE_LEFT \
                                | AUDIO_LOCATION_SIDE_RIGHT \
                                | AUDIO_LOCATION_TOP_FRONT_LEFT \
                                | AUDIO_LOCATION_TOP_FRONT_RIGHT \
                                | AUDIO_LOCATION_TOP_FRONT_CENTER \
                                | AUDIO_LOCATION_TOP_CENTER \
                                | AUDIO_LOCATION_TOP_BACK_LEFT \
                                | AUDIO_LOCATION_TOP_BACK_RIGHT \
                                | AUDIO_LOCATION_TOP_SIDE_LEFT \
                                | AUDIO_LOCATION_TOP_SIDE_RIGHT \
                                | AUDIO_LOCATION_TOP_SIDE_CENTER \
                                | AUDIO_LOCATION_BOTTOM_FRONT_CENTER \
                                | AUDIO_LOCATION_BOTTOM_FRONT_LEFT \
                                | AUDIO_LOCATION_BOTTOM_FRONT_RIGHT \
                                | AUDIO_LOCATION_FRONT_LEFT_WIDER \
                                | AUDIO_LOCATION_FRONT_RIGHT_WIDER \
                                | AUDIO_LOCATION_SURROUND_LEFT \
                                | AUDIO_LOCATION_SURROUND_RIGHT )

/*! Sink/speaker audio Location/s to be renderred locally on this device */
static uint32 sink_audio_location_to_render;

bool PacsAudioLocations_IsAudioLocationValid(uint32 audio_location)
{
    return ((~ALL_AUDIO_LOCATIONS & audio_location) == 0);
}

static uint32 pacsAudioLocations_GetAudioLocationByDeviceSide(bool for_sink)
{
    uint32 audio_locations = 0;

    switch (Multidevice_GetSide())
    {
        case multidevice_side_left:
            audio_locations = PACS_AUDIO_LOCATION_LEFT;
        break;

        case multidevice_side_right:
            audio_locations = PACS_AUDIO_LOCATION_RIGHT;
        break;

        case multidevice_side_both:
            audio_locations = PACS_AUDIO_LOCATION_LEFT;
            if (for_sink)
            {
                audio_locations |= PACS_AUDIO_LOCATION_RIGHT;
            }
        break;

        default:
        break;
    }

    return audio_locations;
}

static uint32 pacsAudioLocations_GetAudioLocationByDeviceType(bool for_sink)
{
    uint32 audio_locations = 0;
    multidevice_type_t type = Multidevice_GetType();

#ifdef INCLUDE_LE_AUDIO_STEREO_CONFIG
    if (!for_sink && type == multidevice_type_pair)
    {
        /* Pair device are in Stereo sink configuration */
        audio_locations = PACS_AUDIO_LOCATION_LEFT;
        return audio_locations;
    }
#endif

    switch (type)
    {
        case multidevice_type_pair:
#ifdef ENABLE_LEA_CIS_DELEGATION
            audio_locations = PACS_AUDIO_LOCATION_LEFT | PACS_AUDIO_LOCATION_RIGHT;
        break;
#endif

        case multidevice_type_single:
            audio_locations = pacsAudioLocations_GetAudioLocationByDeviceSide(for_sink);
        break;

        default:
        break;
    }

    DEBUG_LOG("pacsAudioLocations_GetAudioLocationByDeviceType for_sink: %d, audio_locations: 0x%x", for_sink, audio_locations);
    return audio_locations;
}

void PacsAudioLocations_UpdateSinkLocations(uint32 sink_locations)
{
    DEBUG_LOG("PacsAudioLocations_UpdateSinkLocations sink_locations=%x", sink_locations);

    PanicFalse((~ALL_AUDIO_LOCATIONS & sink_locations) == 0);

    if(sink_locations != LeBapPacsUtilities_GetSinkAudioLocations())
    {
        LeBapPacsUtilities_SetSinkAudioLocations(sink_locations);
    }
    DEBUG_LOG("PacsAudioLocations_UpdateSinkLocations sink_locations=%x", sink_locations);
}

void PacsAudioLocations_UpdateSourceLocations(uint32 source_locations)
{
    DEBUG_LOG("PacsAudioLocations_UpdateSourceLocations source_locations=%x", source_locations);

    PanicFalse((~ALL_AUDIO_LOCATIONS & source_locations) == 0);

    if(source_locations != LeBapPacsUtilities_GetSourceAudioLocations())
    {
        LeBapPacsUtilities_SetSourceAudioLocations(source_locations);
    }
    DEBUG_LOG("PacsAudioLocations_UpdateSourceLocations source_locations=%x", source_locations);
}

uint32 PacsAudioLocations_GetSinkAudioLocationToRender(void)
{
    DEBUG_LOG("PacsAudioLocations_GetAudioLocationToRender sink_audio_location_to_render=%x", sink_audio_location_to_render);

    return sink_audio_location_to_render;
}

void PacsAudioLocations_SetSinkAudioLocationToRender(uint32 audio_location)
{
    sink_audio_location_to_render = audio_location;

    DEBUG_LOG("PacsAudioLocations_SetAudioLocationToRender sink_audio_location_to_render=0x%x", sink_audio_location_to_render);
}

uint32 PacsAudioLocations_GetPacAudioLocation(bool for_sink_direction)
{
    return for_sink_direction ? LeBapPacsUtilities_GetSinkAudioLocations() : LeBapPacsUtilities_GetSourceAudioLocations();
}

void PacsAudioLocations_Initialise(void)
{
    PacsAudioLocations_UpdateSourceLocations(pacsAudioLocations_GetAudioLocationByDeviceType(FALSE));
    PacsAudioLocations_UpdateSinkLocations(pacsAudioLocations_GetAudioLocationByDeviceType(TRUE));

    /* Initialize default sink audio locations to render based on device type */
    PacsAudioLocations_SetSinkAudioLocationToRender(pacsAudioLocations_GetAudioLocationByDeviceSide(TRUE));
}
#endif
